TODO

library(ggplot2)
library(data.table)

Load all good candidates for all GAGA species (1st filter: Take only good candidates from both databases)

Load all tsv files for the different GAGA ids in a list of data frames.

#tsv2load<-"/Users/lukas/sciebo/Projects/LGT/results/GAGA.LGT/*/results/*.*.lgt.good.candidates.tsv"
tsv2load<-"/Users/Janina/sciebo/GAGA.LGT/*/results/*.*.lgt.good.candidates.tsv"
dataFiles <- lapply(Sys.glob(tsv2load), read.csv,sep="\t")

add the name

Add the GAGA id as a name to the different list elements.

ids<-gsub(".*/(.+-[0-9]+)\\..+.lgt.good.candidates.tsv","\\1",Sys.glob(tsv2load))
type<-gsub(".*/(.+-[0-9]+)\\.(.+).lgt.good.candidates.tsv","\\2",Sys.glob(tsv2load))
names(dataFiles)<-paste(ids,type,sep=".")

Combine all GAGA ids

Combine tsv files from all GAGA ids to one big data frame.

head(df)
head(df)

extract eval

Extract the evalue of the best prokaryotic hit (take eval from column “bestProHit”) Make a new data table (called “bestblasthits”) with the column “besteval” + “bestProHit” from the df

bestblasthits<-read.csv(text=as.character(df$bestProHit),sep = ";",as.is = T,fill = T,blank.lines.skip = F,header=F)
df$besteval<-bestblasthits$V4

extract broad locus start and stop

loci<-read.csv(text=gsub(":","-",df$locus),sep = "-",as.is = T,fill = T,blank.lines.skip = F,header=F)
df$locus.start<-loci$V2
df$locus.end<-loci$V3
df$locus.length<-df$locus.end-df$locus.start

plot overview plots

plot histrograms of different metrics to see how they are distributed.

ggplot(df, aes(x=gc)) +
  geom_histogram(fill="red", alpha=0.5, position="identity")+theme_classic()


ggplot(df, aes(x=ce)) +
  geom_histogram(fill="red", alpha=0.5, position="identity")+theme_classic()


ggplot(df, aes(x=ct4)) +
  geom_histogram(fill="red", alpha=0.5, position="identity")+theme_classic()


ggplot(df, aes(x=ct6)) +
  geom_histogram(fill="red", alpha=0.5, position="identity")+theme_classic()


ggplot(df, aes(x=locus.length)) +
  geom_histogram(fill="red", alpha=0.5, position="identity")+theme_classic()


ggplot(df, aes(x=cand.end-cand.start)) +
  geom_histogram(fill="red", alpha=0.5, position="identity")+theme_classic()


df$log.besteval<- -log(df$besteval,10)
df$log.besteval[df$log.besteval==Inf]<-max(df$log.besteval[df$log.besteval!=Inf])+1
ggplot(df, aes(x=df$log.besteval)) +
  geom_histogram(fill="red", alpha=0.5, position="identity")+theme_classic()

Test different filters

What if we filter by evalue (evalue< 1e-50), ct4 (ct4>0.25) and the length of the candidate (length>100)?

dfFilter2<-subset(df,log.besteval>50 & ct4>0.25 & cand.end-cand.start>100 & locus.start > 1000 & locus.length<50000)

What if we remove anything at the beginnign of a scaffold and loci over 50 kb? These are more likely to be misassemblies. (Note that this still leaves in candidates at the very end of scaffolds, which also are more likely misassemblies).

dfFilter2<-subset(df,log.besteval>20 & ct4>0.25 & cand.end-cand.start>100 & locus.start > 1000)

Summarize candidates in close proximity into one larger locus

One row per broad start/stop coordinates

required libraries

library(dplyr)
library(ggrepel)
  1. Create a data frame that has in each row one larger locus (often containing several lgt candidates).
# keep one row per larger locus and paste together all the info for the different LGT candidates contained in this locus

## https://stackoverflow.com/questions/40033625/concatenating-all-rows-within-a-group-using-dplyr/40033725
dfC <- dplyr::group_by(df, locus) %>%
        dplyr::summarise_each(funs(paste(unique(.), collapse = ";")))

# filter this by locus dataframe to only keep loci that have at least one good candidate (i.e. that was contained in the dfFilter2 dataframe)
dfC.filtered<-subset(dfC,locus %in% unique(dfFilter2$locus),select=c(locus,.id,cand.locus,cand.start,cand.end,bestProHit,scaffold,start,end,gc,gcs,ce))

# save data frame to file
write.table(dfC.filtered,"/Users/lukas/sciebo/Projects/LGT/results/GAGA.LGT.filtered.tsv",sep="\t",quote = F,row.names = F)

# for plotting
# split the unfiltered large df dataframe by "locus" into a list of dataframes (one list element per locus)
dfSplit<-split(df,f=paste(df$.id,df$locus,sep="."))

# filter the list of dataframes to only retain those that contain a LGT from the dfFilter2 dataframe
dfSplit.filtered<-dfSplit[unique(paste(dfFilter2$.id,dfFilter2$locus,sep="."))]

Plot each locus

# Define a function containing a ggplot command. This function will be applied to each element of dfSplit.filtered (the list of dataframes)
plotLGTlocus<-function(locusData){
    locusData$logeval<- -log(locusData$besteval,10)
    locusData$logeval[!is.finite(locusData$logeval)]<- 350
    locusData$species<-substr(gsub(".*;","",locusData$bestProHit),1,20)
    ggplotLGT<-ggplot(locusData)+
          geom_rect(aes(xmin=cand.start,xmax=cand.end,ymin=1,ymax=0,fill=logeval),size=0)+
          coord_cartesian(xlim=c(min(locusData$locus.start),max(locusData$locus.end)),ylim=c(0,5))+
          geom_text_repel(
            aes(x=cand.start,y=1,label=species),
            force_pull   = 0, # do not pull toward data points
            nudge_y      = 0.5,
            direction    = "x",
            angle        = 90,
            hjust        = 0,
            segment.size = 0.2,
            max.iter = 1e4, max.time = 1
            )+
          scale_fill_gradient(low="steelblue",high = "red",limits = c(20,350),na.value = "grey90")+
          ggtitle(locusData$.id[1])+
          theme_classic()+
          xlab(locusData$locus[1])+
          guides(y="none")+
          ylab("")+
          theme(legend.position="right")
    return(ggplotLGT)
  }
# test the plotting function
plotLGTlocus(dfSplit.filtered[[1]])
# run plotting function over all elements in the dfSplit.filtered list, i.e. over all loci.
list.of.plots<-lapply(dfSplit.filtered,FUN=plotLGTlocus)

# save all plots (adjust path to your system)
lapply(1:length(list.of.plots), function(i){
      ggsave(filename=paste0("/Users/lukas/sciebo/Projects/LGT/results/LGT.filtered/",gsub(":","-",names(list.of.plots)[i]),".pdf"), plot=list.of.plots[[i]])
  })
LS0tCnRpdGxlOiAiUiBOb3RlYm9vazogQW5hbHlzZSBMR1QgY2FuZGlkYXRlcyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKCiMjIFRPRE8KLSBncm91cCBieSBzdGFydC9lbmQgLSBkb25lIC0KLSBwbG90IGJ5IGxhcmdlIGNhbmRpZGF0ZQotIGluY2x1ZGUgbm9BbnQgLSBkb25lIC0KLSBzZXQgdGhyZXNob2xkcyBmb3IgZXZhbHVhdGlvbiBvZiBjYW5kaWRhdGVzIAoKYGBge3J9CmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShkYXRhLnRhYmxlKQpgYGAKCiMgTG9hZCBhbGwgZ29vZCBjYW5kaWRhdGVzIGZvciBhbGwgR0FHQSBzcGVjaWVzICgxc3QgZmlsdGVyOiBUYWtlIG9ubHkgZ29vZCBjYW5kaWRhdGVzIGZyb20gYm90aCBkYXRhYmFzZXMpCgpMb2FkIGFsbCB0c3YgZmlsZXMgZm9yIHRoZSBkaWZmZXJlbnQgR0FHQSBpZHMgaW4gYSBsaXN0IG9mIGRhdGEgZnJhbWVzLgpgYGB7cn0KI3RzdjJsb2FkPC0iL1VzZXJzL2x1a2FzL3NjaWViby9Qcm9qZWN0cy9MR1QvcmVzdWx0cy9HQUdBLkxHVC8qL3Jlc3VsdHMvKi4qLmxndC5nb29kLmNhbmRpZGF0ZXMudHN2Igp0c3YybG9hZDwtIi9Vc2Vycy9KYW5pbmEvc2NpZWJvL0dBR0EuTEdULyovcmVzdWx0cy8qLioubGd0Lmdvb2QuY2FuZGlkYXRlcy50c3YiCmRhdGFGaWxlcyA8LSBsYXBwbHkoU3lzLmdsb2IodHN2MmxvYWQpLCByZWFkLmNzdixzZXA9Ilx0IikKYGBgCgojIGFkZCB0aGUgbmFtZSAKQWRkIHRoZSBHQUdBIGlkIGFzIGEgbmFtZSB0byB0aGUgZGlmZmVyZW50IGxpc3QgZWxlbWVudHMuCmBgYHtyfQppZHM8LWdzdWIoIi4qLyguKy1bMC05XSspXFwuLisubGd0Lmdvb2QuY2FuZGlkYXRlcy50c3YiLCJcXDEiLFN5cy5nbG9iKHRzdjJsb2FkKSkKdHlwZTwtZ3N1YigiLiovKC4rLVswLTldKylcXC4oLispLmxndC5nb29kLmNhbmRpZGF0ZXMudHN2IiwiXFwyIixTeXMuZ2xvYih0c3YybG9hZCkpCm5hbWVzKGRhdGFGaWxlcyk8LXBhc3RlKGlkcyx0eXBlLHNlcD0iLiIpCmBgYAoKCiMgQ29tYmluZSBhbGwgR0FHQSBpZHMKQ29tYmluZSB0c3YgZmlsZXMgZnJvbSBhbGwgR0FHQSBpZHMgdG8gb25lIGJpZyBkYXRhIGZyYW1lLgpgYGB7cn0KCmRmPC1yYmluZGxpc3QoZGF0YUZpbGVzLGlkY29sID0gVCkKCmBgYAoKCmBgYHtyfQpoZWFkKGRmKQpgYGAKCgojIGV4dHJhY3QgZXZhbApFeHRyYWN0IHRoZSBldmFsdWUgb2YgdGhlIGJlc3QgcHJva2FyeW90aWMgaGl0ICh0YWtlIGV2YWwgZnJvbSBjb2x1bW4gImJlc3RQcm9IaXQiKQpNYWtlIGEgbmV3IGRhdGEgdGFibGUgKGNhbGxlZCAiYmVzdGJsYXN0aGl0cyIpIHdpdGggdGhlIGNvbHVtbiAiYmVzdGV2YWwiICsgImJlc3RQcm9IaXQiIGZyb20gdGhlIGRmCmBgYHtyfQpiZXN0Ymxhc3RoaXRzPC1yZWFkLmNzdih0ZXh0PWFzLmNoYXJhY3RlcihkZiRiZXN0UHJvSGl0KSxzZXAgPSAiOyIsYXMuaXMgPSBULGZpbGwgPSBULGJsYW5rLmxpbmVzLnNraXAgPSBGLGhlYWRlcj1GKQpkZiRiZXN0ZXZhbDwtYmVzdGJsYXN0aGl0cyRWNApgYGAKCiMgZXh0cmFjdCBicm9hZCBsb2N1cyBzdGFydCBhbmQgc3RvcCAKYGBge3J9CmxvY2k8LXJlYWQuY3N2KHRleHQ9Z3N1YigiOiIsIi0iLGRmJGxvY3VzKSxzZXAgPSAiLSIsYXMuaXMgPSBULGZpbGwgPSBULGJsYW5rLmxpbmVzLnNraXAgPSBGLGhlYWRlcj1GKQpkZiRsb2N1cy5zdGFydDwtbG9jaSRWMgpkZiRsb2N1cy5lbmQ8LWxvY2kkVjMKZGYkbG9jdXMubGVuZ3RoPC1kZiRsb2N1cy5lbmQtZGYkbG9jdXMuc3RhcnQKCmBgYAoKIyBwbG90IG92ZXJ2aWV3IHBsb3RzCnBsb3QgaGlzdHJvZ3JhbXMgb2YgZGlmZmVyZW50IG1ldHJpY3MgdG8gc2VlIGhvdyB0aGV5IGFyZSBkaXN0cmlidXRlZC4KYGBge3J9CmdncGxvdChkZiwgYWVzKHg9Z2MpKSArCiAgZ2VvbV9oaXN0b2dyYW0oZmlsbD0icmVkIiwgYWxwaGE9MC41LCBwb3NpdGlvbj0iaWRlbnRpdHkiKSt0aGVtZV9jbGFzc2ljKCkKCmdncGxvdChkZiwgYWVzKHg9Y2UpKSArCiAgZ2VvbV9oaXN0b2dyYW0oZmlsbD0icmVkIiwgYWxwaGE9MC41LCBwb3NpdGlvbj0iaWRlbnRpdHkiKSt0aGVtZV9jbGFzc2ljKCkKCmdncGxvdChkZiwgYWVzKHg9Y3Q0KSkgKwogIGdlb21faGlzdG9ncmFtKGZpbGw9InJlZCIsIGFscGhhPTAuNSwgcG9zaXRpb249ImlkZW50aXR5IikrdGhlbWVfY2xhc3NpYygpCgpnZ3Bsb3QoZGYsIGFlcyh4PWN0NikpICsKICBnZW9tX2hpc3RvZ3JhbShmaWxsPSJyZWQiLCBhbHBoYT0wLjUsIHBvc2l0aW9uPSJpZGVudGl0eSIpK3RoZW1lX2NsYXNzaWMoKQoKZ2dwbG90KGRmLCBhZXMoeD1sb2N1cy5sZW5ndGgpKSArCiAgZ2VvbV9oaXN0b2dyYW0oZmlsbD0icmVkIiwgYWxwaGE9MC41LCBwb3NpdGlvbj0iaWRlbnRpdHkiKSt0aGVtZV9jbGFzc2ljKCkKCmdncGxvdChkZiwgYWVzKHg9Y2FuZC5lbmQtY2FuZC5zdGFydCkpICsKICBnZW9tX2hpc3RvZ3JhbShmaWxsPSJyZWQiLCBhbHBoYT0wLjUsIHBvc2l0aW9uPSJpZGVudGl0eSIpK3RoZW1lX2NsYXNzaWMoKQoKZGYkbG9nLmJlc3RldmFsPC0gLWxvZyhkZiRiZXN0ZXZhbCwxMCkKZGYkbG9nLmJlc3RldmFsW2RmJGxvZy5iZXN0ZXZhbD09SW5mXTwtbWF4KGRmJGxvZy5iZXN0ZXZhbFtkZiRsb2cuYmVzdGV2YWwhPUluZl0pKzEKZ2dwbG90KGRmLCBhZXMoeD1kZiRsb2cuYmVzdGV2YWwpKSArCiAgZ2VvbV9oaXN0b2dyYW0oZmlsbD0icmVkIiwgYWxwaGE9MC41LCBwb3NpdGlvbj0iaWRlbnRpdHkiKSt0aGVtZV9jbGFzc2ljKCkKYGBgCgoKIyBUZXN0IGRpZmZlcmVudCBmaWx0ZXJzCgpXaGF0IGlmIHdlIGZpbHRlciBieSBldmFsdWUgKGV2YWx1ZTwgMWUtNTApLCBjdDQgKGN0ND4wLjI1KSBhbmQgdGhlIGxlbmd0aCBvZiB0aGUgY2FuZGlkYXRlIChsZW5ndGg+MTAwKT8KYGBge3J9CmRmRmlsdGVyPC1zdWJzZXQoZGYsbG9nLmJlc3RldmFsPjUwICYgY3Q0PjAuMjUgJiBjYW5kLmVuZC1jYW5kLnN0YXJ0PjEwMCkKYGBgCgpXaGF0IGlmIHdlIHJlbW92ZSBhbnl0aGluZyBhdCB0aGUgYmVnaW5uaWduIG9mIGEgc2NhZmZvbGQgYW5kIGxvY2kgb3ZlciA1MCBrYj8KVGhlc2UgYXJlIG1vcmUgbGlrZWx5IHRvIGJlIG1pc2Fzc2VtYmxpZXMuIChOb3RlIHRoYXQgdGhpcyBzdGlsbCBsZWF2ZXMgaW4gY2FuZGlkYXRlcyBhdCB0aGUgdmVyeSBlbmQgb2Ygc2NhZmZvbGRzLCB3aGljaCBhbHNvIGFyZSBtb3JlIGxpa2VseSBtaXNhc3NlbWJsaWVzKS4KYGBge3J9CmRmRmlsdGVyMjwtc3Vic2V0KGRmLGxvZy5iZXN0ZXZhbD4yMCAmIGN0ND4wLjI1ICYgY2FuZC5lbmQtY2FuZC5zdGFydD4xMDAgJiBsb2N1cy5zdGFydCA+IDEwMDApCmBgYAoKCiMgU3VtbWFyaXplIGNhbmRpZGF0ZXMgaW4gY2xvc2UgcHJveGltaXR5IGludG8gb25lIGxhcmdlciBsb2N1cwpPbmUgcm93IHBlciBicm9hZCBzdGFydC9zdG9wIGNvb3JkaW5hdGVzCgojIyByZXF1aXJlZCBsaWJyYXJpZXMKYGBge3J9CmxpYnJhcnkoZHBseXIpCmxpYnJhcnkoZ2dyZXBlbCkKYGBgCgoxLiBDcmVhdGUgYSBkYXRhIGZyYW1lIHRoYXQgaGFzIGluIGVhY2ggcm93IG9uZSBsYXJnZXIgbG9jdXMgKG9mdGVuIGNvbnRhaW5pbmcgc2V2ZXJhbCBsZ3QgY2FuZGlkYXRlcykuCmBgYHtyfQojIGtlZXAgb25lIHJvdyBwZXIgbGFyZ2VyIGxvY3VzIGFuZCBwYXN0ZSB0b2dldGhlciBhbGwgdGhlIGluZm8gZm9yIHRoZSBkaWZmZXJlbnQgTEdUIGNhbmRpZGF0ZXMgY29udGFpbmVkIGluIHRoaXMgbG9jdXMKCiMjIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzQwMDMzNjI1L2NvbmNhdGVuYXRpbmctYWxsLXJvd3Mtd2l0aGluLWEtZ3JvdXAtdXNpbmctZHBseXIvNDAwMzM3MjUKZGZDIDwtIGRwbHlyOjpncm91cF9ieShkZiwgbG9jdXMpICU+JQogICAgICAgIGRwbHlyOjpzdW1tYXJpc2VfZWFjaChmdW5zKHBhc3RlKHVuaXF1ZSguKSwgY29sbGFwc2UgPSAiOyIpKSkKCiMgZmlsdGVyIHRoaXMgYnkgbG9jdXMgZGF0YWZyYW1lIHRvIG9ubHkga2VlcCBsb2NpIHRoYXQgaGF2ZSBhdCBsZWFzdCBvbmUgZ29vZCBjYW5kaWRhdGUgKGkuZS4gdGhhdCB3YXMgY29udGFpbmVkIGluIHRoZSBkZkZpbHRlcjIgZGF0YWZyYW1lKQpkZkMuZmlsdGVyZWQ8LXN1YnNldChkZkMsbG9jdXMgJWluJSB1bmlxdWUoZGZGaWx0ZXIyJGxvY3VzKSxzZWxlY3Q9Yyhsb2N1cywuaWQsY2FuZC5sb2N1cyxjYW5kLnN0YXJ0LGNhbmQuZW5kLGJlc3RQcm9IaXQsc2NhZmZvbGQsc3RhcnQsZW5kLGdjLGdjcyxjZSkpCgojIHNhdmUgZGF0YSBmcmFtZSB0byBmaWxlCndyaXRlLnRhYmxlKGRmQy5maWx0ZXJlZCwiL1VzZXJzL2x1a2FzL3NjaWViby9Qcm9qZWN0cy9MR1QvcmVzdWx0cy9HQUdBLkxHVC5maWx0ZXJlZC50c3YiLHNlcD0iXHQiLHF1b3RlID0gRixyb3cubmFtZXMgPSBGKQoKIyBmb3IgcGxvdHRpbmcKIyBzcGxpdCB0aGUgdW5maWx0ZXJlZCBsYXJnZSBkZiBkYXRhZnJhbWUgYnkgImxvY3VzIiBpbnRvIGEgbGlzdCBvZiBkYXRhZnJhbWVzIChvbmUgbGlzdCBlbGVtZW50IHBlciBsb2N1cykKZGZTcGxpdDwtc3BsaXQoZGYsZj1wYXN0ZShkZiQuaWQsZGYkbG9jdXMsc2VwPSIuIikpCgojIGZpbHRlciB0aGUgbGlzdCBvZiBkYXRhZnJhbWVzIHRvIG9ubHkgcmV0YWluIHRob3NlIHRoYXQgY29udGFpbiBhIExHVCBmcm9tIHRoZSBkZkZpbHRlcjIgZGF0YWZyYW1lCmRmU3BsaXQuZmlsdGVyZWQ8LWRmU3BsaXRbdW5pcXVlKHBhc3RlKGRmRmlsdGVyMiQuaWQsZGZGaWx0ZXIyJGxvY3VzLHNlcD0iLiIpKV0KCgpgYGAKCiMgUGxvdCBlYWNoIGxvY3VzCgpgYGB7cn0KIyBEZWZpbmUgYSBmdW5jdGlvbiBjb250YWluaW5nIGEgZ2dwbG90IGNvbW1hbmQuIFRoaXMgZnVuY3Rpb24gd2lsbCBiZSBhcHBsaWVkIHRvIGVhY2ggZWxlbWVudCBvZiBkZlNwbGl0LmZpbHRlcmVkICh0aGUgbGlzdCBvZiBkYXRhZnJhbWVzKQpwbG90TEdUbG9jdXM8LWZ1bmN0aW9uKGxvY3VzRGF0YSl7CiAgICBsb2N1c0RhdGEkbG9nZXZhbDwtIC1sb2cobG9jdXNEYXRhJGJlc3RldmFsLDEwKQogICAgbG9jdXNEYXRhJGxvZ2V2YWxbIWlzLmZpbml0ZShsb2N1c0RhdGEkbG9nZXZhbCldPC0gMzUwCiAgICBsb2N1c0RhdGEkc3BlY2llczwtc3Vic3RyKGdzdWIoIi4qOyIsIiIsbG9jdXNEYXRhJGJlc3RQcm9IaXQpLDEsMjApCiAgICBnZ3Bsb3RMR1Q8LWdncGxvdChsb2N1c0RhdGEpKwogICAgICAgICAgZ2VvbV9yZWN0KGFlcyh4bWluPWNhbmQuc3RhcnQseG1heD1jYW5kLmVuZCx5bWluPTEseW1heD0wLGZpbGw9bG9nZXZhbCksc2l6ZT0wKSsKICAgICAgICAgIGNvb3JkX2NhcnRlc2lhbih4bGltPWMobWluKGxvY3VzRGF0YSRsb2N1cy5zdGFydCksbWF4KGxvY3VzRGF0YSRsb2N1cy5lbmQpKSx5bGltPWMoMCw1KSkrCiAgICAgICAgICBnZW9tX3RleHRfcmVwZWwoCiAgICAgICAgICAgIGFlcyh4PWNhbmQuc3RhcnQseT0xLGxhYmVsPXNwZWNpZXMpLAogICAgICAgICAgICBmb3JjZV9wdWxsICAgPSAwLCAjIGRvIG5vdCBwdWxsIHRvd2FyZCBkYXRhIHBvaW50cwogICAgICAgICAgICBudWRnZV95ICAgICAgPSAwLjUsCiAgICAgICAgICAgIGRpcmVjdGlvbiAgICA9ICJ4IiwKICAgICAgICAgICAgYW5nbGUgICAgICAgID0gOTAsCiAgICAgICAgICAgIGhqdXN0ICAgICAgICA9IDAsCiAgICAgICAgICAgIHNlZ21lbnQuc2l6ZSA9IDAuMiwKICAgICAgICAgICAgbWF4Lml0ZXIgPSAxZTQsIG1heC50aW1lID0gMQogICAgICAgICAgICApKwogICAgICAgICAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3c9InN0ZWVsYmx1ZSIsaGlnaCA9ICJyZWQiLGxpbWl0cyA9IGMoMjAsMzUwKSxuYS52YWx1ZSA9ICJncmV5OTAiKSsKICAgICAgICAgIGdndGl0bGUobG9jdXNEYXRhJC5pZFsxXSkrCiAgICAgICAgICB0aGVtZV9jbGFzc2ljKCkrCiAgICAgICAgICB4bGFiKGxvY3VzRGF0YSRsb2N1c1sxXSkrCiAgICAgICAgICBndWlkZXMoeT0ibm9uZSIpKwogICAgICAgICAgeWxhYigiIikrCiAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb249InJpZ2h0IikKICAgIHJldHVybihnZ3Bsb3RMR1QpCiAgfQpgYGAKCmBgYHtyfQojIHRlc3QgdGhlIHBsb3R0aW5nIGZ1bmN0aW9uCnBsb3RMR1Rsb2N1cyhkZlNwbGl0LmZpbHRlcmVkW1sxXV0pCmBgYAoKCmBgYHtyfQojIHJ1biBwbG90dGluZyBmdW5jdGlvbiBvdmVyIGFsbCBlbGVtZW50cyBpbiB0aGUgZGZTcGxpdC5maWx0ZXJlZCBsaXN0LCBpLmUuIG92ZXIgYWxsIGxvY2kuCmxpc3Qub2YucGxvdHM8LWxhcHBseShkZlNwbGl0LmZpbHRlcmVkLEZVTj1wbG90TEdUbG9jdXMpCgojIHNhdmUgYWxsIHBsb3RzIChhZGp1c3QgcGF0aCB0byB5b3VyIHN5c3RlbSkKbGFwcGx5KDE6bGVuZ3RoKGxpc3Qub2YucGxvdHMpLCBmdW5jdGlvbihpKXsKICAgICAgZ2dzYXZlKGZpbGVuYW1lPXBhc3RlMCgiL1VzZXJzL2x1a2FzL3NjaWViby9Qcm9qZWN0cy9MR1QvcmVzdWx0cy9MR1QuZmlsdGVyZWQvIixnc3ViKCI6IiwiLSIsbmFtZXMobGlzdC5vZi5wbG90cylbaV0pLCIucGRmIiksIHBsb3Q9bGlzdC5vZi5wbG90c1tbaV1dKQogIH0pCmBgYAo=